import time
import Queue
import thread
import urllib

import gtk
import gobject

# Baird's original module provides support for GtkMozEmbed as well.
# I've simplified this to use WebKit only, just to make things a little
# easier for me to understand -- it should be possible to restore the
# Mozilla bindings if desired.
#
# Substantially refactored to make Browser interface more object-oriented.

import webkit

class WebkitBrowser(object):
    """
    Web browser tool for GTK.
    
    WebKit implementation.
    """
    def __init__(self, message_queue):
        self.view = webkit.WebView()
        self.message_queue = message_queue
        
        def title_changed(widget, frame, title):
            if title != 'null': message_queue.put(title)
            
        self.view.connect('title-changed', title_changed)
        
    def open(self, uri):
        print "Trying to open '%s'" % uri
        self.view.open(uri)

    def web_receive(self):
        if self.message_queue.empty():
            return None
        else:
            msg = self.message_queue.get()
            if echo: print '>>>', msg
            return msg

    def web_send(self, msg):
        if echo: print '<<<', msg
        asynchronous_gtk_message(self.view.execute_script)(msg)
            
  
Browser = WebkitBrowser # This is where we could switch in an alternate browser class

def asynchronous_gtk_message(fun):

    def worker((function, args, kwargs)):
        apply(function, args, kwargs)

    def fun2(*args, **kwargs):
        gobject.idle_add(worker, (fun, args, kwargs))

    return fun2


def synchronous_gtk_message(fun):

    class NoResult: pass

    def worker((R, function, args, kwargs)):
        R.result = apply(function, args, kwargs)

    def fun2(*args, **kwargs):
        class R: result = NoResult
        gobject.idle_add(worker, (R, fun, args, kwargs))
        while R.result is NoResult: time.sleep(0.01)
        return R.result

    return fun2
    
        

def launch_browser(uri, quit_function=None, keyqueue=None):
    message_queue = Queue.Queue()
    browser = Browser(message_queue)

    # GTK stuff - currently very simple
    # TODO: We should probably add pop-up direct controls here
    window = gtk.Window()
    box = gtk.VBox(homogeneous=False, spacing=0)
    window.add(box)
    
    # Simple queue for keyboard events
    if keyqueue is not None:
        def keypressed(widget, event):
            keyqueue.put(event)
            return True
        window.connect('key_press_event', keypressed)
        
    if False: #quit_function is not None:
        # Obligatory "File: Quit" menu
        # {
        file_menu = gtk.Menu()
        quit_item = gtk.MenuItem('Quit')
        accel_group = gtk.AccelGroup()
        quit_item.add_accelerator('activate',
                                  accel_group,
                                  ord('Q'),
                                  gtk.gdk.CONTROL_MASK,
                                  gtk.ACCEL_VISIBLE)
        window.add_accel_group(accel_group)
        file_menu.append(quit_item)
        quit_item.connect('activate', quit_function)
        quit_item.show()
        #
        menu_bar = gtk.MenuBar()
        menu_bar.show()
        file_item = gtk.MenuItem('File')
        file_item.show()
        file_item.set_submenu(file_menu)
        menu_bar.append(file_item)
        # }
        #box.pack_start(menu_bar, expand=False, fill=True, padding=0)
        #menu_bar.show_all()

    if quit_function is not None:
        window.connect('destroy', quit_function)
    

    box.pack_start(browser.view, expand=True, fill=True, padding=0)
    window.set_default_size(800, 600)
    #window.fullscreen()
    window.show_all()
    
    browser.open(uri)
    return browser


def start_gtk_thread():
    # Start GTK in its own thread:
    gtk.gdk.threads_init()
    thread.start_new_thread(gtk.main, ())

def kill_gtk_thread():
    asynchronous_gtk_message(gtk.main_quit)()

